#include "drv_pcie_irq.h"
// #include "drv_xcan.h"

struct pcie_irq_t pcie_irq;

int init_pcie_irq(struct pci_dev *pdev, struct pcie_irq_ctrl_t *pctrl, 
                  int mode, int vec_start, int vec_end, 
                  irq_handler_t handler, const char *name, 
                  void *dev, int dev_offset, void __iomem *reg_base)
{
    int ret, i;
    bool auto_select = false;
    const char *mode_name;

    /* 检查参数是否有效 */
    if (!pdev || !pctrl || !handler || !name || !dev || !reg_base) {
        pr_err("Invalid parameters for %s, %p, %p, %p, %p, %p, %p", 
               __func__, pdev, pctrl, handler, name, dev, reg_base);
        return -EINVAL;
    }

    dev_dbg(&pdev->dev, "initializing IRQ mode %d, vectors %d-%d", 
            mode, vec_start, vec_end);

    /* 初始化中断结构 */
    pctrl->irq->pdev = pdev;
    strscpy(pctrl->name, name, sizeof(pctrl->name));
    pctrl->vec_start = vec_start;
    pctrl->vec_end = vec_end;
    pctrl->handler = handler;

    /* 检查是否已经初始化 */
    if (pctrl->irq->vec_num > 0) {
        dev_dbg(&pdev->dev, "IRQ already initialized, reusing existing setup");
        goto setup_irqs;
    }

    /* 确定中断模式 */
    switch (mode) {
    case PCI_IRQ_MSIX:
        mode_name = "MSI-X";
        pctrl->irq->vec_num = PCIE_IRQ_MAX_VEC_MSIX;
        ret = pci_alloc_irq_vectors(pdev, 1, pctrl->irq->vec_num, PCI_IRQ_MSIX);
        break;
    case PCI_IRQ_MSI:
        mode_name = "MSI";
        pctrl->irq->vec_num = PCIE_IRQ_MAX_VEC_MSI;
        ret = pci_alloc_irq_vectors(pdev, 1, pctrl->irq->vec_num, PCI_IRQ_MSI);
        break;
    case PCI_IRQ_LEGACY:
        mode_name = "Legacy";
        pctrl->irq->vec_num = PCIE_IRQ_MAX_VEC_LGCY;
        ret = pci_alloc_irq_vectors(pdev, 1, pctrl->irq->vec_num, PCI_IRQ_LEGACY);
        break;
    default:
        dev_warn(&pdev->dev, "invalid IRQ mode %d, auto-selecting", mode);
        auto_select = true;
        mode_name = "Auto-select";
        
        /* 自动选择模式: 从 MSI-X 开始尝试 */
        pctrl->irq->vec_num = PCIE_IRQ_MAX_VEC_MSIX;
        ret = pci_alloc_irq_vectors(pdev, 1, pctrl->irq->vec_num, PCI_IRQ_MSIX);
        if (ret > 0) {
            mode = PCI_IRQ_MSIX;
            break;
        }
        
        /* MSI-X 失败，尝试 MSI */
        pctrl->irq->vec_num = PCIE_IRQ_MAX_VEC_MSI;
        ret = pci_alloc_irq_vectors(pdev, 1, pctrl->irq->vec_num, PCI_IRQ_MSI);
        if (ret > 0) {
            mode = PCI_IRQ_MSI;
            break;
        }
        
        /* MSI 失败，尝试 Legacy */
        pctrl->irq->vec_num = PCIE_IRQ_MAX_VEC_LGCY;
        ret = pci_alloc_irq_vectors(pdev, 1, pctrl->irq->vec_num, PCI_IRQ_LEGACY);
        if (ret < 0) {
            dev_err(&pdev->dev, "failed to allocate any IRQ vectors");
            return ret;
        }
        mode = PCI_IRQ_LEGACY;
        break;
    }

    /* 处理分配结果 */
    if (ret < 0) {
        dev_err(&pdev->dev, "failed to allocate %s IRQ vectors: %d", mode_name, ret);
        return ret;
    }

    /* 设置实际的中断模式 */
    pctrl->irq->mode = mode;
    if (mode == PCI_IRQ_LEGACY) {
        pctrl->irq->vec_num = 1; /* Legacy 模式只有 1 个向量 */
    } else if (ret > 0) {
        pctrl->irq->vec_num = ret; /* 实际分配的向量数量 */
    }

    dev_info(&pdev->dev, "IRQ using %s with %d vectors", mode_name, pctrl->irq->vec_num);

setup_irqs:
    /* 设置中断标志 */
    pctrl->irq->flags = (pctrl->irq->mode == PCI_IRQ_LEGACY) ? IRQF_SHARED : 0;

    /* 注册中断处理程序 */
    if (pctrl->irq->mode == PCI_IRQ_LEGACY) {
        /* Legacy 中断只需要注册一个处理程序 */
        i = 0;
        pctrl->irq->vector[i] = pci_irq_vector(pdev, i);
        if (pctrl->irq->vector[i] < 0) {
            dev_err(&pdev->dev, "invalid IRQ vector for index %d", i);
            ret = -EINVAL;
            goto free_irq_vectors;
        }

        snprintf(pctrl->irq->name[i], sizeof(pctrl->irq->name[i]), "%s%d", name, i);
        
        ret = request_irq(pctrl->irq->vector[i], handler, pctrl->irq->flags,
                         pctrl->irq->name[i], dev + dev_offset);
        if (ret) {
            dev_err(&pdev->dev, "failed to request IRQ %d: %d", 
                    pctrl->irq->vector[i], ret);
            goto free_irq_vectors;
        }

        dev_dbg(&pdev->dev, "registered legacy IRQ: vector=%d, pctrl=%d, name=%s",
                i, pctrl->irq->vector[i], pctrl->irq->name[i]);
        pctrl->irq->num = +1;
    } else {
        /* MSI/MSI-X 需要为每个向量注册处理程序 */
        for (i = vec_start; i <= vec_end && i < pctrl->irq->vec_num; i++) {
            pctrl->irq->vector[i] = pci_irq_vector(pdev, i);
            if (pctrl->irq->vector[i] < 0) {
                dev_err(&pdev->dev, "invalid IRQ vector for index %d", i);
                ret = -EINVAL;
                goto free_irqs;
            }

            snprintf(pctrl->irq->name[i], sizeof(pctrl->irq->name[i]), 
                    "%s%d", name, (i - vec_start));
            
            ret = request_irq(pctrl->irq->vector[i], handler, pctrl->irq->flags,
                             pctrl->irq->name[i], dev + dev_offset * (i - vec_start));
            if (ret) {
                dev_err(&pdev->dev, "failed to request IRQ %d for vector %d: %d",
                        pctrl->irq->vector[i], i, ret);
                goto free_irqs;
            }

            dev_dbg(&pdev->dev, "registered IRQ: vector=%d, pctrl=%d, name=%s",
                    i, pctrl->irq->vector[i], pctrl->irq->name[i]);
            pctrl->irq->num++;
        }
    }

    dev_info(&pdev->dev, "IRQ %s initialized", pctrl->name);
    return 0;

free_irqs:
    /* 清理已注册的中断 */
    if (pctrl->irq->mode == PCI_IRQ_LEGACY) {
        /* Legacy 模式只需要释放单个中断 */
        if (pctrl->irq->vector[0] > 0) {
            dev_dbg(&pdev->dev, "freeing legacy IRQ %d", pctrl->irq->vector[0]);
            free_irq(pctrl->irq->vector[0], dev + dev_offset);
            pctrl->irq->vector[0] = 0;
        }
    } else {
        /* MSI/MSI-X 模式需要释放多个中断 */
        int j;
        for (j = i - 1; j >= vec_start; j--) {
            if (pctrl->irq->vector[j] > 0) {
                dev_dbg(&pdev->dev, "freeing IRQ %d for vector %d", 
                        pctrl->irq->vector[j], j);
                free_irq(pctrl->irq->vector[j], dev + dev_offset * (j - vec_start));
                pctrl->irq->vector[j] = 0;
            }
        }
    }
free_irq_vectors:
    pci_free_irq_vectors(pdev);

    return ret;
}

void exit_pcie_irq(struct pcie_irq_ctrl_t *pctrl, void *dev, int dev_offset)
{
    int i;
    struct pci_dev *pdev = pctrl->irq->pdev;

    /* 检查参数是否有效 */
    if (!pctrl || !pctrl->irq || !dev) {
        pr_err("Invalid parameters for %s, %p, %p, %p", 
               __func__, pctrl, pctrl->irq, dev);
        return;
    }

    dev_dbg(&pdev->dev, "Cleaning up IRQ resources");

    /* 释放所有已注册的中断处理程序 */
    if (pctrl->irq->mode == PCI_IRQ_LEGACY) {
        /* Legacy 模式只有一个中断 */
        if (pctrl->irq->vector[0] > 0) {
            dev_dbg(&pdev->dev, "Freeing legacy IRQ %d", pctrl->irq->vector[0]);
            free_irq(pctrl->irq->vector[0], dev + dev_offset);
            pctrl->irq->vector[0] = 0;
            pctrl->irq->num--;
        }
    } else {
        /* MSI/MSI-X 模式有多个中断向量 */
        for (i = pctrl->vec_start; i <= pctrl->vec_end && i < pctrl->irq->vec_num; i++) {
            if (pctrl->irq->vector[i] > 0) {
                dev_dbg(&pdev->dev, "Freeing IRQ %d for vector %d", 
                        pctrl->irq->vector[i], i);
                free_irq(pctrl->irq->vector[i], dev + dev_offset * (i - pctrl->vec_start));
                pctrl->irq->vector[i] = 0;
                pctrl->irq->num--;
            }
        }
    }

    /* 如果所有中断都已释放，则释放中断向量 */
    if (pctrl->irq->num <= 0) {
        pci_free_irq_vectors(pdev);
        dev_dbg(&pdev->dev, "Freed IRQ vectors");
        
        /* 重置中断信息 */
        pctrl->irq->mode = 0;
        pctrl->irq->vec_num = 0;
    } else {
        dev_warn(&pdev->dev, "%d IRQs still allocated", pctrl->irq->num);
    }

    dev_dbg(&pdev->dev, "IRQ cleanup completed");
}
